#include "Graphics.h"
#include <d3dx9.h>
//---------------------------------------------------------------------------------------------//
Graphics::Graphics()
{
	dxObject = NULL;
	dxDevice = NULL;
	
	pVertexObject = NULL; 
	pVertexBuffer = NULL;

	lastTexture = NULL;
}
//---------------------------------------------------------------------------------------------//
bool Graphics::Init(HWND hwnd)
{
	//	inicializo el dxObject.
	//	D3D_SDK_VERSION verifica que se hayan agregado los headers correctos
	dxObject = Direct3DCreate9(D3D_SDK_VERSION);
	// si no lo pudo inisializar retorna falso
	if(!dxObject)
		return false;
	// D3DPRESENT_PARAMETERS es una struct de los parametros de la instancia de directX
	D3DPRESENT_PARAMETERS PresentParams;
	// Sets the first "sizeof(D3DPRESENT_PARAMETERS)" bytes of the block of memory pointed by "PresentParams" to the specified value (0).
	memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS));
	
	// seteo los parametros con los que voy a crear el dxDevice
	PresentParams.Windowed = TRUE;				
	PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
	PresentParams.EnableAutoDepthStencil = TRUE;
	PresentParams.AutoDepthStencilFormat = D3DFMT_D16;
	
	// crea el DX device con los parametros de PresentParams en el howndler de la ventana y lo deposita en el dxDevice
	dxObject->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &PresentParams, &dxDevice);
	
	if(!vertexBufferMgr.Create(dxDevice))
		 return false;

	if(!vertexBufferMgrUV.Create(dxDevice))
		 return false;
	
	SetMatrixMode(VIEW_MATRIX);
	LoadIdentity();

	SetMatrixMode(WORLD_MATRIX);
	LoadIdentity();

	D3DXMATRIX mat;

	D3DXMatrixOrthoLH(&mat, 800, 600, -25, 25);
	dxDevice->SetTransform(D3DTS_PROJECTION, &mat);

	dxDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	dxDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	dxDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
	dxDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
	//dxDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	dxDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	dxDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
	dxDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	dxDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	dxDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
	dxDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);

	return true;
}
//---------------------------------------------------------------------------------------------//
void Graphics::Clear() 
{
	dxDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 100, 34),1.0f, 0);
}
//---------------------------------------------------------------------------------------------//
void Graphics::BeginScene()
{
	dxDevice->BeginScene();
}
//---------------------------------------------------------------------------------------------//
void Graphics::EndScene()
{
	dxDevice->EndScene();
}
//---------------------------------------------------------------------------------------------//
void Graphics::Present(HWND hwnd)
{
	dxDevice->Present(NULL, NULL, NULL, NULL);
	ValidateRect(hwnd, NULL);
}
//---------------------------------------------------------------------------------------------//
void Graphics::DeInit()
{
	dxDevice->Release();
	dxObject->Release();
}
//---------------------------------------------------------------------------------------------//
bool Graphics::DrawElements(unsigned int cantidad, D3DVertex* vertices, PRIM_TYPE primType)
{
	vertexBufferMgr.Bind();

	if(!vertexBufferMgr.Draw(vertices,(D3DPRIMITIVETYPE)primType,cantidad))
		 return false;

	return true;	
}
//---------------------------------------------------------------------------------------------//
bool Graphics::DrawSpriteElements(unsigned int cantidad, D3DVertexUV* vertices, PRIM_TYPE primType)
{
	 vertexBufferMgrUV.Bind();

	 if(!vertexBufferMgrUV.Draw(vertices,(D3DPRIMITIVETYPE)primType,cantidad))
		 return false;
	 
	 //dxDevice->DrawPrimitive((D3DPRIMITIVETYPE)primType, 0, cantidad);

	 return true;	
}
//---------------------------------------------------------------------------------------------//
void Graphics::SetMatrixMode(MATRIX_MODES mode)
{
	currentMatrixMode = mode;
}
//---------------------------------------------------------------------------------------------//
void Graphics::LoadIdentity()
{
	D3DXMatrixIdentity( & dxMatrix );

	switch(currentMatrixMode)
	{
	case WORLD_MATRIX:
		dxDevice->SetTransform(D3DTS_WORLD, & dxMatrix);
		break;
	case VIEW_MATRIX:
		{
			D3DXVECTOR3 dxEyePosition(0.0f, 0.0f, -5.0f);
			D3DXVECTOR3 dxLookPosition(0.0f, 0.0f, 0.0f);
			D3DXVECTOR3 dxUpVertex(0.0f, 1.0f, 0.0f);

			D3DXMatrixLookAtLH(& dxMatrix, & dxEyePosition, & dxLookPosition, & dxUpVertex);
			dxDevice->SetTransform(D3DTS_VIEW, & dxMatrix);
			break;
		}
	case PROYECTION_MATRIX:
		dxDevice->SetTransform(D3DTS_PROJECTION, & dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
void Graphics::Translate(float x, float y, float z)
{
	D3DXMatrixTranslation( & dxMatrix, x,y,z );

	switch(currentMatrixMode)
	{
	case WORLD_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_WORLD, & dxMatrix);
		break;
	case VIEW_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_VIEW, & dxMatrix);
		break;
	case PROYECTION_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_PROJECTION, & dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
void Graphics::RotateZ(float z)
{
	D3DXMatrixRotationZ( & dxMatrix, z);

	switch(currentMatrixMode)
	{
	case WORLD_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_WORLD, & dxMatrix);
		break;
	case VIEW_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_VIEW, & dxMatrix);
		break;
	case PROYECTION_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_PROJECTION, & dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
void Graphics::Scale(float x, float y)
{
	D3DXMatrixScaling( & dxMatrix, x, y , 1.0f);

	switch(currentMatrixMode)
	{
	case WORLD_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_WORLD, & dxMatrix);
		break;
	case VIEW_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_VIEW, & dxMatrix);
		break;
	case PROYECTION_MATRIX:
		dxDevice->MultiplyTransform(D3DTS_PROJECTION, & dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
Texture* Graphics::LoadTexture(std::wstring path, DWORD colorKey)
{
	D3DXIMAGE_INFO info;
	LPDIRECT3DTEXTURE9 tex;

	HRESULT hr = D3DXCreateTextureFromFileEx(
		dxDevice,
		path.c_str(),
		0,
		0,
		0,
		D3DUSAGE_DYNAMIC,
		D3DFMT_FROM_FILE,
		D3DPOOL_DEFAULT,
		D3DX_FILTER_NONE,
		D3DX_FILTER_NONE,
		colorKey,
		&info,
		NULL,
		&tex);

	if (hr == D3D_OK)
	{
		Texture* aux = new Texture();
		aux->data = tex;
		aux->height = info.Height;
		aux->width = info.Width;
		aux->path = path;
		
		return aux;
	}
	
	return NULL;
}
//---------------------------------------------------------------------------------------------//
void Graphics::SetTexture(Texture* pTexture)
{ 
	if (lastTexture != pTexture)
	{
		if (pTexture != NULL) 
		{
			dxDevice->SetTexture(0,pTexture->data);
		}
		else
		{
			dxDevice->SetTexture(0,NULL);
		}					

		lastTexture = pTexture;
	}
}